const redis = require('../config/redis')
const logger = require('./logger')

class Cache {
  /**
   * 设置缓存
   * @param {string} key - 缓存键
   * @param {string} value - 缓存值
   * @param {number} ttl - 过期时间(秒)，默认1小时
   */
  static async set(key, value, ttl = 3600) {
    try {
      if (typeof value === 'object') {
        value = JSON.stringify(value)
      }
      if (ttl > 0) {
        await redis.setex(key, ttl, value)
      } else {
        await redis.set(key, value)
      }
    } catch (error) {
      logger.error('Cache set error:', error)
      throw error
    }
  }

  /**
   * 获取缓存
   * @param {string} key - 缓存键
   * @returns {Promise<any>} 缓存值
   */
  static async get(key) {
    try {
      const value = await redis.get(key)
      if (!value) return null
      
      try {
        return JSON.parse(value)
      } catch {
        return value
      }
    } catch (error) {
      logger.error('Cache get error:', error)
      return null
    }
  }

  /**
   * 删除缓存
   * @param {string} key - 缓存键
   */
  static async del(key) {
    try {
      await redis.del(key)
    } catch (error) {
      logger.error('Cache delete error:', error)
      throw error
    }
  }

  /**
   * 批量删除匹配的缓存
   * @param {string} pattern - 匹配模式
   */
  static async delByPattern(pattern) {
    try {
      const keys = await redis.keys(pattern)
      if (keys.length > 0) {
        await redis.del(...keys)
      }
    } catch (error) {
      logger.error('Cache batch delete error:', error)
      throw error
    }
  }

  /**
   * 检查缓存是否存在
   * @param {string} key - 缓存键
   * @returns {Promise<boolean>} 是否存在
   */
  static async exists(key) {
    try {
      return await redis.exists(key) === 1
    } catch (error) {
      logger.error('Cache exists error:', error)
      return false
    }
  }

  /**
   * 批量设置缓存
   * @param {Object} keyValues - 键值对对象
   * @param {number} ttl - 过期时间(秒)
   */
  static async mset(keyValues, ttl = 3600) {
    try {
      const pipeline = redis.pipeline()
      Object.entries(keyValues).forEach(([key, value]) => {
        if (typeof value === 'object') {
          value = JSON.stringify(value)
        }
        if (ttl > 0) {
          pipeline.setex(key, ttl, value)
        } else {
          pipeline.set(key, value)
        }
      })
      await pipeline.exec()
    } catch (error) {
      logger.error('Cache mset error:', error)
      throw error
    }
  }

  /**
   * 批量获取缓存
   * @param {string[]} keys - 缓存键数组
   * @returns {Promise<Object>} 键值对对象
   */
  static async mget(keys) {
    try {
      const values = await redis.mget(keys)
      const result = {}
      keys.forEach((key, index) => {
        const value = values[index]
        if (value) {
          try {
            result[key] = JSON.parse(value)
          } catch {
            result[key] = value
          }
        }
      })
      return result
    } catch (error) {
      logger.error('Cache mget error:', error)
      return {}
    }
  }

  /**
   * 获取分布式锁
   * @param {string} key - 锁键
   * @param {number} ttl - 锁过期时间(秒)
   * @returns {Promise<boolean>} 是否获取成功
   */
  static async lock(key, ttl = 30) {
    try {
      const lockKey = `lock:${key}`
      const result = await redis.set(lockKey, '1', 'EX', ttl, 'NX')
      return result === 'OK'
    } catch (error) {
      logger.error('Cache lock error:', error)
      return false
    }
  }

  /**
   * 释放分布式锁
   * @param {string} key - 锁键
   */
  static async unlock(key) {
    try {
      const lockKey = `lock:${key}`
      await redis.del(lockKey)
    } catch (error) {
      logger.error('Cache unlock error:', error)
      throw error
    }
  }

  /**
   * 缓存预热
   * @param {Object} data - 预热数据，键值对对象
   * @param {number} ttl - 过期时间(秒)
   */
  static async warmup(data, ttl = 3600) {
    try {
      await this.mset(data, ttl)
      logger.info('Cache warmup completed')
    } catch (error) {
      logger.error('Cache warmup error:', error)
      throw error
    }
  }

  /**
   * 设置空值缓存(防止缓存穿透)
   * @param {string} key - 缓存键
   * @param {number} ttl - 过期时间(秒)，默认5分钟
   */
  static async setNil(key, ttl = 300) {
    try {
      await this.set(key, 'NIL', ttl)
    } catch (error) {
      logger.error('Cache setNil error:', error)
      throw error
    }
  }

  /**
   * 获取Redis客户端实例
   * @returns {Redis} Redis客户端实例
   */
  static getClient() {
    return redis
  }
}

module.exports = Cache 